#pragma once

#include "log.hpp"
#include "Epoll.hpp"
#include "Sock.hpp"
#include <functional>
#include <unistd.h>
#include <cassert>
class EpollServer
{
    using func_t = std::function<void(std::string)>;

public:
    static const int default_port;
    static const int gnum;

public:
    EpollServer(func_t HandlerRequst, const int &port = 8080)
        : _port(port), _HandlerRequest(HandlerRequst), _revs_num(gnum)
    {
        _revs = new struct epoll_event[_revs_num];

        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);

        _epfd = Epoll::CreateEpoll();
        logMessage(DEBUG, "init success, listensock: %d, epfd: %d", _listensock, _epfd);

        if (!Epoll::CtlEpoll(_epfd, EPOLL_CTL_ADD, _listensock, EPOLLIN))
        {
            logMessage(ERROR, "%s", "CTLEpoll--：listensock添加失败");
            exit(6);
        }
        logMessage(DEBUG, "add listensock to epoll success.");
    }

    void Accepter(int listensock)
    {
        std::string clientip;
        uint16_t clientport = 0;
        int sock = Sock::Accept(_listensock,&clientip,&clientport);

        if(!Epoll::CtlEpoll(_epfd,EPOLL_CTL_ADD,sock,EPOLLIN))
        {
            logMessage(ERROR, "%s", "Accpet--:sock添加到epoll失败");
            return;
        }
        logMessage(DEBUG, "add new sock : %d to epoll success", sock); 
    }
    void Recver(int sock)
    {
        char buffer[256];
        ssize_t n = recv(sock,buffer,sizeof(buffer)-1,0);

        if(n>0)
        {
            buffer[n] = 0;
            _HandlerRequest(buffer);
        }
        else if(n==0)
        {
            bool res = Epoll::CtlEpoll(_epfd,EPOLL_CTL_DEL,sock,0);
            if(res == false)
                std::cout<<"epoll 去除错误";
            assert(res);
            (void)res;
            close(sock);
            logMessage(NORMAL, "client %d quit, me too...", sock);
        }
        else
        {
            bool res = Epoll::CtlEpoll(_epfd,EPOLL_CTL_DEL,sock,0);
            assert(res);
            (void)res;
            close(sock);
            logMessage(NORMAL, "client recv %d error, close error sock", sock);

        }
    }
    void HandlerEvents(int n)
    {
        assert(n > 0);
        for (int i = 0; i < n; i++)
        {
            int sock = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;

            if (revents & EPOLLIN)
            {
                if (sock == _listensock)
                    Accepter(_listensock);
                else
                    Recver(sock);
            }
            if (revents & EPOLLOUT)
            {
                // TODO?
            }
        }
    }
    void LoopOnce(int timeout)
    {
        int n = Epoll::WaitEpoll(_epfd, _revs, _revs_num, timeout);

        switch (n)
        {
        case 0:
            logMessage(DEBUG, "timeout...");
            break;
        case -1:
            logMessage(WARNING, "epoll wait error: %s", strerror(errno));
            break;
        default:
            logMessage(DEBUG, "get a event");
            HandlerEvents(n);
            break;
        }
    }

    void Start()
    {
        int timeout = -1;
        while (true)
            LoopOnce(timeout);
    }
    ~EpollServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_epfd >= 0)
            close(_epfd);
        if (_revs)
            delete[] _revs;
    }

private:
    int _listensock;
    int _epfd;
    uint16_t _port;
    struct epoll_event *_revs;
    int _revs_num;
    func_t _HandlerRequest;
};
const int EpollServer::default_port = 8080;
const int EpollServer::gnum = 64;